﻿//You can change this to feet your needs, just please keep giving credits to the author
//Thanks
//	DarkAngel  ( DarkAngel@IdleZone.Org )

using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.WindowsMobile.Forms;
using Microsoft.WindowsMobile.Status;
using Sensors;

namespace DarkRuler
{
	public partial class FormMain : Form
	{
		#region Delegate to avoid cross thread exception
		private delegate void ChangeVisibleStateDelegate(Control obj, bool VisibleState);
		private void ChangeVisibleState(Control obj, bool VisibleState)
		{
			if (this.InvokeRequired)
			{
				this.BeginInvoke(new ChangeVisibleStateDelegate(ChangeVisibleState), new object[] { obj, VisibleState });
			}
			else
			{
				obj.Visible = VisibleState;
			}
		}
		#endregion

		#region HTC Sensors
		//used to change the box size when turning around the dPad
		Sensors.HTCNavSensor mySensor;
		Sensors.IGSensor myGSensor = Sensors.GSensorFactory.CreateGSensor();
		bool UseSensors = false;
		#endregion
		#region Local Variables
		//Allow to know how to interpret the "mouse" actions (box or line move ;))
		bool BoxModeSelected = true;
		//If auto-update is ON and Azure is ok (network available), will be true : this allow to stop properly the Azure threads ^^
		bool AzureOk = false;
		//Allow to know when mouse is moving for line drawing (start/end points)
		bool IsMouseMoving = false;
		#endregion
		#region HardCoded values
		const double InchesSize = 0.3937008;	//Inches Size compared to CentiMeters Size
		const string tmpFile = "Temp\\DarkRuler.jpg";	//Temp image file (deleted on exit)
		#endregion

		/// <summary>
		/// Main constructor
		/// </summary>
		public FormMain()
		{
			InitializeComponent();
			//Default mode is "BOXMove"
			pictureBoxBOX.Image = Properties.Resources.Box_ON;
			pictureBoxLINE.Image = Properties.Resources.Line_OFF;

			//Hide all buttons but the "camera" one ;)
			pictureBoxBOX.Visible = false;
			pictureBoxLINE.Visible = false;
			buttonValidatePicture.Visible = false;

			#region HTC Sensors
			try
			{
				mySensor = new Sensors.HTCNavSensor(this);
				UseSensors = true;
			}
			catch
			{
				UseSensors = false;
			}
			if (UseSensors)
			{
				mySensor.Rotated += new Sensors.NavSensorMoveHandler(mySensor_Rotated);
				myGSensor.OrientationChanged += new Sensors.OrientationChangedHandler(myGSensor_OrientationChanged);
			}
			#endregion
			this.WindowState = FormWindowState.Maximized;	//put the window to max, see if needed...

			if (Config.AutoUpdate)
			{
				//Start the AutoUpdate check thread for async check ;)
				new System.Threading.Thread(new System.Threading.ThreadStart(CheckUpdate)).Start();
			}
		}

		#region HTC Sensors
		/// <summary>
		/// should be called when sensor detects change of orientation...
		/// </summary>
		/// <param name="sender"></param>
		/// <remarks>To be tested, looks to be inactive???</remarks>
		void myGSensor_OrientationChanged(Sensors.IGSensor sender)
		{
			//if (pictureBox1.IsPictureOk)
			//{
			//  if (BoxModeSelected)
			//  {
			//    Sensors.GVector vect = sender.GetGVector();
			//    pictureBox1.BoxPoint.X += (int)vect.X;
			//    pictureBox1.BoxPoint.Y += (int)vect.Y;
			//  }
			//}
		}
		/// <summary>
		/// called when finger turns around the dPad ;)
		/// </summary>
		/// <param name="rotationsPerSecond"></param>
		/// <param name="radialDelta"></param>
		void mySensor_Rotated(double rotationsPerSecond, double radialDelta)
		{
			if (pictureBox1.IsPictureOk)
			{
				if (BoxModeSelected)
				{
					//Zoom of the box
					pictureBox1.ChangeBoxSize(radialDelta);
				}
				CalcAndDisp();
			}
			else if (pictureBox1.IsPictureTaken)
			{
				//Zoom of the picture
				pictureBox1.ChangePictureSize(radialDelta);
			}
		}
		#endregion

		#region PictureBox events, here is managed the move of box/line
		private Point previousMousePosition = Point.Empty;
		private Point MouseDistance = Point.Empty;
		private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
		{
			if (pictureBox1.IsPictureOk)
			{
				//Move of Line/Box
				if (BoxModeSelected)
					pictureBox1.MoveBox(e.X - 50, e.Y - 50);
				else if (IsMouseMoving)
				{
					pictureBox1.EndPoint = new Point(e.X, e.Y);
					pictureBox1.Invalidate();//force picturebox to be repaint
				}
				CalcAndDisp();
			}
			else if (pictureBox1.IsPictureTaken)
			{
				//Move of the picture
				if (!previousMousePosition.IsEmpty)
				{
					//Mouse is moving...yeah stupid to put this kind of test in the "mouseMove" event lol
					pictureBox1.MovePicture(MouseDistance.X + (previousMousePosition.X - e.X), MouseDistance.Y + (previousMousePosition.Y - e.Y));
				}
			}
		}
		private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
		{
			if (pictureBox1.IsPictureOk)
			{
				if (!BoxModeSelected)
				{
					IsMouseMoving = true;
					pictureBox1.StartPoint = new Point(e.X, e.Y);
				}
			}
			else if (pictureBox1.IsPictureTaken)
				{
				previousMousePosition = new Point(e.X, e.Y);
			}
		}
		private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
		{
			if (pictureBox1.IsPictureOk)
			{
				if (!BoxModeSelected)
				{
					IsMouseMoving = false;
					pictureBox1.EndPoint = new Point(e.X, e.Y);
					CalcAndDisp();
				}
			}
			else if (pictureBox1.IsPictureTaken)
			{
				if (MouseDistance.IsEmpty)
					MouseDistance = new Point(previousMousePosition.X - e.X, previousMousePosition.Y - e.Y);
				else
					MouseDistance = new Point(MouseDistance.X + (previousMousePosition.X - e.X), MouseDistance.Y + (previousMousePosition.Y - e.Y));
				previousMousePosition = Point.Empty;
			}
		}
		#endregion

		/// <summary>
		/// Calculate and Display the size
		/// </summary>
		private void CalcAndDisp()
		{
			int LineX = Math.Abs(pictureBox1.EndPoint.X - pictureBox1.StartPoint.X);
			int LineY = Math.Abs(pictureBox1.EndPoint.Y - pictureBox1.StartPoint.Y);

			double len = Math.Sqrt(Math.Pow(LineX, 2) + Math.Pow(LineY, 2));	//yeah happy pithagore theory

			labelResult.Text = Math.Round(len, 2) + " px";
			labelResult.Text += " - " + Math.Round(((len * Config.BoxSizeInCm) / pictureBox1.GetBoxXSize()), 2).ToString() + " cm";
			labelResult.Text += " - " + Math.Round(((len * Config.BoxSizeInCm) / pictureBox1.GetBoxXSize()) * InchesSize, 2).ToString() + " inch";
		}

		#region Clean Up
		/// <summary>
		/// Clean Up!!
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		/// <remarks>before the window loose focus</remarks>
		private void FormMain_Closing(object sender, CancelEventArgs e)
		{
			if (AzureOk)
			{
				Azure.DataAccess.SendStopSignal();
				Azure.DataAccess.WaitForEnd();
			}
		}
		/// <summary>
		/// Clean up!!
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		/// <remarks>after the window lost focus, this will be "background"</remarks>
		private void FormMain_Closed(object sender, EventArgs e)
		{
			//Drop the temporary file for pictures
			if (System.IO.File.Exists(tmpFile))
				System.IO.File.Delete(tmpFile);
			#region HTC Sensors
			//Try to cleanup HTC Sensors (if not used will fails in the catch ^^)
			try
			{
				myGSensor.Dispose();
			}
			catch { }
			#endregion
		}
		#endregion

		#region Menu Actions
		/// <summary>
		/// Exit
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void menuItemExit_Click(object sender, EventArgs e)
		{
			this.Close();
		}
		/// <summary>
		/// Launch the config box
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void menuItemOptions_Click(object sender, EventArgs e)
		{
			bool previousAutoUpdate = Config.AutoUpdate;
			new FormOptions().ShowDialog();
			if (!previousAutoUpdate && Config.AutoUpdate)
			{
				//Update mode is activated, start the CheckUpdate thread!
				new System.Threading.Thread(new System.Threading.ThreadStart(CheckUpdate)).Start();
			}
			if (pictureBox1.IsPictureTaken)
			{
				ManualMode_PictureMoveX = 0;
				ManualMode_PictureMoveY = 0;

				ManualMode_BoxMoveX = 0;
				ManualMode_BoxMoveY = 0;

				//Small hack for HD : no DPad so provide users 2 buttons for zooming functions!
				buttonZoomIn.Visible = Config.UseButtonsForZoom;
				buttonZoomOut.Visible = Config.UseButtonsForZoom;
			}
		}
		/// <summary>
		/// Launch the "about" box
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void menuItemAbout_Click(object sender, EventArgs e)
		{
			new FormAbout().ShowDialog();
		}
		#endregion

		/// <summary>
		/// Start the photo camera dialog and send the picture to the "MyPictureBox" for display
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void pictureBoxCamera_Click(object sender, EventArgs e)
		{
			pictureBox1.IsPictureTaken = false;
			pictureBox1.IsPictureOk = false;
			pictureBox1.SetBoxSize((float)Config.BoxXSize_InPixel, (float)Config.BoxYSize_InPixel);
			//pictureBox1.LastFile = new Bitmap("test.bmp");
			//pictureBox1.IsPictureTaken = true;
			CameraCaptureDialog cameraCapture = new CameraCaptureDialog();
			cameraCapture.Owner = this;
			if (!System.IO.Directory.Exists("Temp"))
				System.IO.Directory.CreateDirectory("Temp");
			cameraCapture.InitialDirectory = "Temp";
			if (cameraCapture.DefaultFileName != null)
			{
				cameraCapture.DefaultFileName = cameraCapture.DefaultFileName + ".jpg";
			}

			cameraCapture.Title = "DarkRuler";
			cameraCapture.Resolution = new Size(pictureBox1.Width, pictureBox1.Height);
			cameraCapture.Mode = CameraCaptureMode.Still;

			cameraCapture.StillQuality = CameraCaptureStillQuality.Default;

			object cameraEnabled = SystemState.GetValue(SystemProperty.CameraPresent);
			if (null != cameraEnabled && 0 == (int)cameraEnabled)
			{
				MessageBox.Show("The camera is disabled", this.Text,
								MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
				return;
			}

			try
			{
				if (DialogResult.OK == cameraCapture.ShowDialog())
				{
					if (System.IO.File.Exists(tmpFile))
						System.IO.File.Delete(tmpFile);
					System.IO.File.Move(cameraCapture.FileName, tmpFile);
					pictureBox1.LastFile = new Bitmap(tmpFile);	//update the image to display
					pictureBox1.IsPictureTaken = true;
				}
			}
			catch (ArgumentException ex)
			{
				// An invalid argument was specified.
				MessageBox.Show(ex.Message, this.Text, MessageBoxButtons.OK,
						MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
			}
			catch (OutOfMemoryException ex)
			{
				// There is not enough memory to save the image or video.
				MessageBox.Show(ex.Message, this.Text, MessageBoxButtons.OK,
						MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
			}
			catch (InvalidOperationException ex)
			{
				// An unknown error occurred.
				MessageBox.Show(ex.Message, this.Text, MessageBoxButtons.OK,
						MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
			}
			try
			{
				cameraCapture.Dispose();
			}
			catch { }

			//HACK: here I had some strange issue and not always the Start Menu was shown after camera !! so I put the windowState to normal and back to max to be fullscreen ;)
			try
			{
				this.WindowState = FormWindowState.Normal;
			}
			catch { }
			try
			{
				this.WindowState = FormWindowState.Maximized;
			}
			catch { }

			if (pictureBox1.IsPictureTaken)
			{
				ManualMode_PictureMoveX = 0;
				ManualMode_PictureMoveY = 0;

				ManualMode_BoxMoveX = 0;
				ManualMode_BoxMoveY = 0;

				buttonValidatePicture.Width = pictureBoxLINE.Width + pictureBoxLINE.Left;
				buttonValidatePicture.Height = pictureBoxLINE.Height;
				buttonValidatePicture.Visible = true;
				pictureBoxLINE.Visible = false;
				pictureBoxBOX.Visible = false;
				
				//Small hack for HD : no DPad so provide users 2 buttons for zooming functions!
				buttonZoomIn.Height = (int)(ClientRectangle.Height / 14.7);
				buttonZoomOut.Height = buttonZoomIn.Height;
				buttonZoomIn.Width = (int)(ClientRectangle.Width / 7.6);
				buttonZoomOut.Width = buttonZoomIn.Width;
				buttonZoomIn.Visible = Config.UseButtonsForZoom;
				buttonZoomOut.Visible = Config.UseButtonsForZoom;
			}
			pictureBox1.Invalidate();
		}
		private void buttonValidatePicture_Click(object sender, EventArgs e)
		{
			if (pictureBox1.IsPictureTaken)	//idiot test but well...
			{
				pictureBox1.IsPictureOk = true;
				pictureBoxLINE.Visible = true;
				pictureBoxBOX.Visible = true;
				buttonValidatePicture.Visible = false;
			}
		}
		/// <summary>
		/// Switch to BoxMode
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void pictureBoxBOX_Click(object sender, EventArgs e)
		{
			if (!BoxModeSelected)
			{
				BoxModeSelected = !BoxModeSelected;
				pictureBoxBOX.Image = Properties.Resources.Box_ON;
				pictureBoxLINE.Image = Properties.Resources.Line_OFF;
			}
		}

		/// <summary>
		/// Switch to LineMode
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void pictureBoxLINE_Click(object sender, EventArgs e)
		{
			if (BoxModeSelected)
			{
				pictureBoxBOX.Image = Properties.Resources.Box_OFF;
				pictureBoxLINE.Image = Properties.Resources.Line_ON;
				BoxModeSelected = !BoxModeSelected;
			}
		}

		/// <summary>
		/// This check for update in the Azure cloud...
		/// Will switch the "Update" button ON/OFF ^^
		/// </summary>
		private void CheckUpdate()
		{
			try
			{
				Azure.DataAccess.Init();
				bool res = Azure.DataAccess.CheckForUpdate();
				if (res)
				{
					ChangeVisibleState(buttonDoUpdate, true);
				}
				else
				{
					ChangeVisibleState(buttonDoUpdate, false);
				}
				AzureOk = true;
			}
			catch (Exception ex)
			{
				string JustDebug = ex.Message;
				JustDebug += "\n" + ex.StackTrace;
				AzureOk = false;
			}
		}

		/// <summary>
		/// Show UpdateBox of the application...
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void buttonDoUpdate_Click(object sender, EventArgs e)
		{
			new FormUpdate().ShowDialog();
		}

		#region Just for fun display part
		/// <summary>
		/// Small stuff to make the button "Update" to blink...
		/// Yeah this is useless ^^
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void timer1_Tick(object sender, EventArgs e)
		{
			Color tmp = buttonDoUpdate.BackColor;
			buttonDoUpdate.BackColor = buttonDoUpdate.ForeColor;
			buttonDoUpdate.ForeColor = tmp;
			this.Refresh();
		}
		/// <summary>
		/// On resize we replace the buttons of top correctly
		/// This allow to manage more resolution screen than the HTC Diamond
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void FormMain_Resize(object sender, EventArgs e)
		{
			FillButtons(pictureBoxBOX, pictureBoxLINE, buttonDoUpdate, pictureBoxCamera);
		}
		#region Small Hacks to put buttons on a nice place and nice size depends on the screen resolution
		private void FillButtons(params Control[] ctrls)
		{
			int btnWidth = 0;
			int btnHeight = 0;
			if (ctrls.Length != 0)
			{
				//if (btnRatio == 0)
				//	btnRatio = ClientSize.Height - ctrls[0].Size.Height;//Calculate the button height difference with the total height, will be calculate on the first Resize...dumb but if using this function on a windows form (not mobile) it should work as well ^^

				//Calculate the button width depends on screen width and number of buttons and distance from border of the first button
				btnWidth = ClientSize.Width;
				btnWidth -= ((ctrls.Length + 1) * ctrls[0].Location.X);
				btnWidth /= ctrls.Length;

				//btnHeight = ClientSize.Height - btnRatio;
				//v0.4 : try to review the button size...
				btnHeight =pictureBox1.Location.Y-(label2.Location.Y + label2.Height)-5;

				for (int i = 0; i < ctrls.Length; i++)
				{
					ctrls[i].Size = new Size(btnWidth, btnHeight);
					if (i != 0)
						ctrls[i].Location = new Point(ctrls[i - 1].Location.X + btnWidth + ctrls[0].Location.X, ctrls[i].Location.Y);
				}
			}
		}
		#endregion
		#endregion
		bool ManualMode_Move = true;
		int ManualMode_PictureMoveX = 0;
		int ManualMode_PictureMoveY = 0;
		int ManualMode_BoxMoveX = 0;
		int ManualMode_BoxMoveY = 0;
		private void FormMain_KeyDown(object sender, KeyEventArgs e)
		{
			if (pictureBox1.IsPictureOk)
			{
				//Manual move/zoom of box using the keyboard
				if (ManualMode_Move)
				{
					if ((e.KeyCode == System.Windows.Forms.Keys.Up))
					{
						ManualMode_BoxMoveY -= 3;
						pictureBox1.MoveBox(ManualMode_BoxMoveX, ManualMode_BoxMoveY);
					}
					else if ((e.KeyCode == System.Windows.Forms.Keys.Down))
					{
						ManualMode_BoxMoveY += 3;
						pictureBox1.MoveBox(ManualMode_BoxMoveX, ManualMode_BoxMoveY);
					}
					else if ((e.KeyCode == System.Windows.Forms.Keys.Left))
					{
						ManualMode_BoxMoveX -= 3;
						pictureBox1.MoveBox(ManualMode_BoxMoveX, ManualMode_BoxMoveY);
					}
					else if ((e.KeyCode == System.Windows.Forms.Keys.Right))
					{
						ManualMode_BoxMoveX += 3;
						pictureBox1.MoveBox(ManualMode_BoxMoveX, ManualMode_BoxMoveY);
					}
				}
				else
				{
					if ((e.KeyCode == System.Windows.Forms.Keys.Up))
					{
						pictureBox1.ChangeBoxSize(0.1);
					}
					else if ((e.KeyCode == System.Windows.Forms.Keys.Down))
					{
						pictureBox1.ChangeBoxSize(-0.1);
					}
					else if ((e.KeyCode == System.Windows.Forms.Keys.Left))
					{
						pictureBox1.ChangeBoxSize(-0.01);
					}
					else if ((e.KeyCode == System.Windows.Forms.Keys.Right))
					{
						pictureBox1.ChangeBoxSize(0.01);
					}
				}
				if ((e.KeyCode == System.Windows.Forms.Keys.Enter))
				{
					ManualMode_Move = !ManualMode_Move;
				}
			} 
			else if (pictureBox1.IsPictureTaken)
			{
				//Manual move/zoom of picture using the keyboard
				if (ManualMode_Move)
				{
					if ((e.KeyCode == System.Windows.Forms.Keys.Up))
					{
						ManualMode_PictureMoveY += 3;
						pictureBox1.MovePicture(ManualMode_PictureMoveX, ManualMode_PictureMoveY);
					}
					else if ((e.KeyCode == System.Windows.Forms.Keys.Down))
					{
						ManualMode_PictureMoveY -= 3;
						pictureBox1.MovePicture(ManualMode_PictureMoveX, ManualMode_PictureMoveY);
					}
					else if ((e.KeyCode == System.Windows.Forms.Keys.Left))
					{
						ManualMode_PictureMoveX += 3;
						pictureBox1.MovePicture(ManualMode_PictureMoveX, ManualMode_PictureMoveY);
					}
					else if ((e.KeyCode == System.Windows.Forms.Keys.Right))
					{
						ManualMode_PictureMoveX -= 3;
						pictureBox1.MovePicture(ManualMode_PictureMoveX, ManualMode_PictureMoveY);
					}
				}
				else
				{
					if ((e.KeyCode == System.Windows.Forms.Keys.Up))
					{
						pictureBox1.ChangePictureSize(0.1);
					}
					else if ((e.KeyCode == System.Windows.Forms.Keys.Down))
					{
						pictureBox1.ChangePictureSize(-0.1);
					}
					else if ((e.KeyCode == System.Windows.Forms.Keys.Left))
					{
						pictureBox1.ChangePictureSize(0.01);
					}
					else if ((e.KeyCode == System.Windows.Forms.Keys.Right))
					{
						pictureBox1.ChangePictureSize(-0.01);
					}
				}
				if ((e.KeyCode == System.Windows.Forms.Keys.Enter))
				{
					ManualMode_Move = !ManualMode_Move;
				}
			}
		}

		private void FormMain_Load(object sender, EventArgs e)
		{
			pictureBox1.LastFile = Properties.Resources.MainPicture;
		}

		private void buttonZoomIn_Click(object sender, EventArgs e)
		{
			if (pictureBox1.IsPictureOk)
			{
				pictureBox1.ChangeBoxSize(0.1);
			}
			else if (pictureBox1.IsPictureTaken)
			{
				pictureBox1.ChangePictureSize(0.1);
			}
		}

		private void buttonZoomOut_Click(object sender, EventArgs e)
		{
			if (pictureBox1.IsPictureOk)
			{
				pictureBox1.ChangeBoxSize(-0.1);
			}
			else if (pictureBox1.IsPictureTaken)
			{
				pictureBox1.ChangePictureSize(-0.1);
			}
		}
	}
}